﻿// http://blog.thekieners.com/2010/02/11/simple-weak-event-listener-for-silverlight/ - Modified

using System;
namespace DeepEarth.Core.Utilities
{
    public class WeakEventListener<TListener, TSource>
    {
        WeakReference weakListener;
        WeakReference weakSource;

        public WeakEventListener(TListener eventListener, TSource eventSource)
        {
            weakSource = new WeakReference(eventSource);
            weakListener = new WeakReference(eventListener);
        }

        private Action<TListener, TSource, EventArgs> eventAction;
        public Action<TListener, TSource, EventArgs> EventAction
        {
            get { return eventAction; }
            set
            {
                //NEVER REMOVE THIS CHECK. IT CAN CAUSE A MEMORY LEAK.
                // May remove this check to enable event handlers with closures (weakreference closures!)
                if (value != null && !value.Method.IsStatic)
                    throw new ArgumentException("The Acutal Handler method must be static (Anonymous Functions in C# are static)");

                eventAction = value;
            }
        }

        // Yeah, I know exactly what I am doing ...
        public Action<TListener, TSource, EventArgs> UnsafeEventAction
        {
            get { return eventAction; }
            set
            {
                // May remove this check to enable event handlers with closures (weakreference closures!)
                eventAction = value;
            }
        }

        private Action<WeakEventListener<TListener, TSource>, TSource> detatchAction;
        public Action<WeakEventListener<TListener, TSource>, TSource> DetatchAction
        {
            get { return detatchAction; }
            set
            {
                // NEVER REMOVE THIS CHECK. IT CAN CAUSE A MEMORY LEAK.
                if (value != null && !value.Method.IsStatic)
                    throw new ArgumentException("OnDetachAction method must be static otherwise the event WeakEventListner cannot guarantee to unregister the handler.");

                detatchAction = value;
            }
        }

         
        public void OnEvent(object source, EventArgs e)
        {
            // actual listener may be GCed after a call to isAlive, to test for null instead)
            if (weakListener.Target != null && EventAction != null)
            {
                EventAction((TListener)weakListener.Target, (TSource)source, e);
            }
            else
            {
                Detatch();
            }
        }

        private void Detatch()
        {
            if (this.weakSource.Target != null)
            {
                detatchAction(this, (TSource)this.weakSource.Target);
            }
        }
    }
}
